#include "Precompiled.h"
#include "Renderer.h"

Sandbox::Renderer::Renderer()
{
	PrintToDebugWindowOnly8("Sandbox. Creating renderer.");
	InitializeCriticalSection(&m_lock);
}

Sandbox::Renderer::~Renderer()
{
	PrintToDebugWindowOnly8("Sandbox. Deleting renderer.");
	DeleteCriticalSection(&m_lock);
}

void Sandbox::Renderer::CreateDeviceResources()
{
	PrintToDebugWindowOnly8("Sandbox. Creating device resources.");

	{ // Create rasterizer state
		Sehnsucht::Resource::RasterizerStateDescrition rasterDesc;
		ZeroValue(&rasterDesc);

		rasterDesc.AntialiasedLineEnable = false;
		rasterDesc.CullMode = D3D11_CULL_BACK;
		rasterDesc.DepthBias = 0;
		rasterDesc.DepthBiasClamp = 0.0f;
		rasterDesc.DepthClipEnable = true;
		rasterDesc.FillMode = D3D11_FILL_SOLID;
		rasterDesc.FrontCounterClockwise = true;
		//rasterDesc.FrontCounterClockwise = false;
		rasterDesc.MultisampleEnable = false;
		rasterDesc.ScissorEnable = false;
		rasterDesc.SlopeScaledDepthBias = 0.0f;

		Sehnsucht::ThrowIfFailed(m_d3dDevice->CreateRasterizerState1(
			&rasterDesc, &m_rasterizerCcw
			));
	}
	{ // Create alpha on blend state
		Sehnsucht::Resource::BlendStateDescrition blendStateDescription;
		ZeroValue(&blendStateDescription);

		// Create an alpha enabled blend state description.
		blendStateDescription.RenderTarget[0].BlendEnable = TRUE;
		blendStateDescription.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
		blendStateDescription.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
		blendStateDescription.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
		blendStateDescription.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
		blendStateDescription.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
		blendStateDescription.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
		blendStateDescription.RenderTarget[0].RenderTargetWriteMask = 0x0f;

		m_d3dDevice->CreateBlendState1(&blendStateDescription, m_blendingEnabled.GetAddressOf()); // !supp win7
	}
}

void TraverseSceneChild( 
	_In_ Eifersucht::SceneChild *localRoot, 
	_In_ uint32 depth
	)
{
	static char8 s_msg[1024];

	auto numChildren = localRoot->GetChildrenCount();
	for (decltype(numChildren) i = 0; i < numChildren; i++)
	{
		String8 header = "", footer = ""; 
		for (decltype(depth) j = 0; j < depth; j++) header += ">>";

		auto child = (*localRoot->GetChildAt(i));
		auto name = child->GetName();

		switch (child->GetChildContextType())
		{
		case Eifersucht::SceneChildContextType::Bone:
			{
				auto skeleton = child->GetTypedChildContext<Eifersucht::SkeletonContext>();
				auto connections = skeleton->GetConnections(); auto numConnections = connections->size();
				{
					StringStream8 sss; sss.clear();
					sss << " (Bone) C=" << numConnections;
					sss << " T<" << child->LclTranslation.x <<","; 
					sss << child->LclTranslation.y <<","; 
					sss << child->LclTranslation.z <<">"; 
					sss << " R<" << child->LclRotation.x <<","; 
					sss << child->LclRotation.y <<","; 
					sss << child->LclRotation.z <<">"; 

					footer = sss.str();
				}

			} break;

		case Eifersucht::SceneChildContextType::Mesh:
			{
				auto mesh = child->GetTypedChildContext<Eifersucht::MeshContext>();
				{
					StringStream8 sss; sss.clear();
					sss << " (Mesh) S=" << mesh->lDeformation.vnSkin.size() << " "; 
					for ( auto skin : mesh->lDeformation.vnSkin )
					{ // start for each [skin]
						sss << "{ B=" << skin->vnBones.size() << " => "; 
						for ( auto bone : skin->vnBones )
						{ // start for each [bone]
							sss << bone->pSkeleton->GetChild()->GetName();
							sss << "[" << bone->uSize << " => ";
							for (uint32 i = 0; i < bone->uSize; i++)
								sss << "<" << bone->pIndices[i] << "," 
									<< bone->pWeights[i] << ">";
							sss << "] ";
						} // end for each [bone]
						sss << "}";
					} // end for each [skin]
					footer = sss.str();
				}
			} break;
		}

		sprintf_s( s_msg, "%s Name=%s%s", 
			header.data(), name.data(),
			footer.data()
			);

		PrintToDebugWindowOnly8(s_msg);
		TraverseSceneChild(child, depth + 1);
	}
}

void Sandbox::Renderer::CreateDeviceIndependentResources()
{
	PrintToDebugWindowOnly8("Sandbox. Creating device independent resources.");

	//m_scene.ImportFbx( L"E:\\DEV\\3dsMax\\Humanoid.FBX" );
	//m_scene.ImportFbx( L"E:\\DEV\\3dsMax\\AnimatedCube-1-Orig-RescaledTimeline-Baked.FBX" );
	//m_scene.ImportFbx( L"E:\\DEV\\3dsMax\\Anim_Cyl_Test_1_wBox.FBX" );
	//m_scene.ImportFbx( L"E:\\DEV\\3dsMax\\WeirdBox-0.FBX" );
	//m_scene.ImportFbx( L"E:\\DEV\\3dsMax\\Anim-TestBox0-AddKeys.FBX" );
	//m_scene.ImportFbx( L"E:\\DEV\\3dsMax\\Anim-TestBox0-NoChanges.FBX" );
	//m_scene.ImportFbx( L"E:\\DEV\\3dsMax\\LegsSimulation2Animated_Frames_15_1_Resc_350_Baked.FBX" );
	
	m_scene.ImportFbx( L"E:\\DEV\\3dsMax\\LegsSimulation2Animated_Frames_15_3.FBX" );
	//m_scene.ImportFbx( L"E:\\DEV\\3dsMax\\LegsSimulation2Animated_Frames_15.Fbx" );
	//m_scene.ImportFbx( L"E:\\DEV\\3dsMax\\Box_2Bones_Animation_Test.Fbx" );

	//m_scene.ImportFbx( L"E:\\DEV\\3dsMax\\LegsSimulation2Animated_Frames_15_1_RescaledTimeline.FBX" );
	//m_scene.ImportFbx( L"E:\\DEV\\3dsMax\\LegsSimulation2Animated_Frames_15_2_RescaledTimeline.FBX" );

	auto sceneRoot = m_scene.GetRootChild();


	//
	PrintToDebugWindowOnly8("\nSandbox. Scene structure.\n");
	TraverseSceneChild( sceneRoot, 1 ); 
	PrintToDebugWindowOnly8("");
	//
	

	m_store.Context3(m_d3dContext.Get());
	m_store.Device3(m_d3dDevice.Get());
	m_store.Scene(&m_scene);
	m_store.Import();

	

}

void Sandbox::Renderer::CreateWindowSizeDependentResources()
{
	PrintToDebugWindowOnly8("Sandbox. Creating window size dependent resources.");
}

void Sandbox::Renderer::Initialize()
{
	PrintToDebugWindowOnly8("Sandbox. Initializing renderer.");
	EnterCriticalSection(&m_lock);

	DirectXBaseDesktop::Initialize();

	CreateDeviceIndependentResources();
	CreateDeviceResources();
	CreateWindowSizeDependentResources();

	LeaveCriticalSection(&m_lock);
}

void Sandbox::Renderer::UpdateForWindowSizeChange()
{
	PrintToDebugWindowOnly8("Sandbox. Updating renderer on window size changed.");
	EnterCriticalSection(&m_lock);

	DirectXBaseDesktop::UpdateForWindowSizeChange();

	m_windowSizeChangedArgs.Dim.y = m_d3dRenderTargetSize.height;
	m_windowSizeChangedArgs.Dim.x = m_d3dRenderTargetSize.width;
	m_windowSizeChangedArgs.Dpi.y = m_dpi;
	m_windowSizeChangedArgs.Dpi.x = m_dpi;

	LeaveCriticalSection(&m_lock);
}